from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import List, Optional
from fastapi.responses import StreamingResponse
import asyncio
import json

from database import SessionLocal
from models.models import LearnUser
from schemas.knowledge_card import KnowledgeCard, KnowledgeCardCreate, GenerateKnowledgeCardRequest
from crud import knowledge_card as crud_knowledge_card
from crud import material as crud_material
from crud.page_record import get_material_card_status, update_material_card_status
from core.agent.knowledgeModel import KnowledgeAnalyzer
from utils.auth import get_current_user
from schemas.material import MaterialContent
from utils.utils import deduplicate_dict_list
from utils.log_manager import app_logger
from config import settings


router = APIRouter(prefix="/card")

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

def window(page_numbers, size=3, overlap=1):
    """
    按固定窗口 + 滑动步长切分页码列表，使用yield方式返回生成器。
    :param page_numbers: List[int] 页码列表（如 [2,3,4,5,6]）
    :param size: int 窗口大小（每组页数）
    :param overlap: int 重叠数量（滑动步长为size-overlap）
    :yield: 每次生成一个包含窗口内页码的列表
    """
    n = len(page_numbers)
    if n == 0:
        return  # 空列表不生成任何窗口
    
    # 如果列表长度小于窗口大小
    if n < size:
        yield page_numbers.copy()
        return 
        
    # 如果列表长度等于窗口大小，只生成一个窗口
    if n == size:
        yield page_numbers.copy()
        return

    # 排序
    page_numbers = list(sorted(page_numbers))
    
    # 计算滑动步长
    step = max(1, size - overlap)  # 确保步长至少为1
    
    # 生成完整窗口
    last_possible_start = n - size
    
    for start in range(0, last_possible_start + 1, step):
        yield page_numbers[start:start + size]
    
    # 确保最后一个窗口包含列表的最后一个元素
    last_start = (last_possible_start // step) * step
    if last_start < last_possible_start:
        yield page_numbers[last_possible_start:last_possible_start + size]


@router.get("/today", response_model=List[KnowledgeCard])
async def get_today_knowledge_cards(
    material_id: Optional[int] = None,
    db: Session = Depends(get_db),
    current_user: LearnUser = Depends(get_current_user)
):
    """
    获取今日创建的知识卡片
    """
    cards = crud_knowledge_card.get_today_knowledge_cards(
        db, current_user.id, material_id
    )
    
    result = []
    for card in cards:
        # 获取材料标题
        material_title = card.material.title if card.material else ""
        
        result.append({
            "id": card.id,
            "title": card.title,
            "summary": card.summary,
            "html_content": card.html_content,
            "page_number": card.page_number,
            "material_title": material_title,
            "created_at": card.created_at,
            "updated_at": card.updated_at
        })
    
    return result

@router.get("/{card_id}", response_model=KnowledgeCard)
async def get_knowledge_card(
    card_id: int,
    db: Session = Depends(get_db),
    current_user: LearnUser = Depends(get_current_user)
):
    """
    获取单个知识卡片
    """
    card = crud_knowledge_card.get_knowledge_card(db, card_id, current_user.id)
    if not card:
        raise HTTPException(status_code=404, detail="知识卡片不存在")
    
    # 获取材料标题
    material_title = card.material.title if card.material else ""
    
    return {
        "id": card.id,
        "title": card.title,
        "summary": card.summary,
        "html_content": card.html_content,
        "page_number": card.page_number,
        "material_title": material_title,
        "created_at": card.created_at,
        "updated_at": card.updated_at
    }

@router.get("/", response_model=List[KnowledgeCard])
async def get_user_knowledge_cards(
    material_id: Optional[int] = None,
    skip: int = 0,
    limit: int = 100,
    db: Session = Depends(get_db),
    current_user: LearnUser = Depends(get_current_user)
):
    """
    获取用户的所有知识卡片，可选择按材料ID筛选
    """
    cards = crud_knowledge_card.get_user_knowledge_cards(
        db, current_user.id, material_id, skip, limit
    )
    
    result = []
    for card in cards:
        # 获取材料标题
        material_title = card.material.title if card.material else ""
        
        result.append({
            "id": card.id,
            "title": card.title,
            "summary": card.summary,
            "html_content": card.html_content,
            "page_number": card.page_number,
            "material_title": material_title,
            "created_at": card.created_at,
            "updated_at": card.updated_at
        })
    
    return result

@router.delete("/{card_id}", response_model=bool)
async def delete_knowledge_card(
    card_id: int,
    db: Session = Depends(get_db),
    current_user: LearnUser = Depends(get_current_user)
):
    """
    删除知识卡片
    """
    result = crud_knowledge_card.delete_knowledge_card(db, card_id, current_user.id)
    if not result:
        raise HTTPException(status_code=404, detail="知识卡片不存在或删除失败")
    return True


@router.post("/generate")
async def generate_knowledge_cards(
    request: GenerateKnowledgeCardRequest,
    db: Session = Depends(get_db),
    current_user: LearnUser = Depends(get_current_user)
):
    """
    以 Server-Sent Events (SSE) 方式生成知识卡片
    每生成一个知识卡片就立即向前端推送
    """
    try:
        # 1. 获取材料信息
        material = crud_material.get_material(db, request.material_id, current_user.id)
        if not material:
            raise HTTPException(status_code=404, detail="Material not found")

        # 2. 获取card_status 为 False 的页码记录
        knowledge_points = get_material_card_status(db, current_user.id)
        if not knowledge_points:
           return []

        # 3. 转换为MaterialContent格式并去重
        materials = [{"material_id": point.material_id, "page_number": point.page_number} 
                    for point in knowledge_points if point.stone]
        materials = deduplicate_dict_list(materials)
        
        app_logger.info(f"要生成知识卡片的材料来源: {materials}")

        # 4. 生成滑动窗口
        page_numbers = [material["page_number"] for material in materials]
        windows = list(window(page_numbers))

        # 5. 初始化知识卡片生成器
        analyzer = KnowledgeAnalyzer(
            api_key=settings.api_key,
            api_base=settings.api_base,
            model_name=settings.api_generate_model
        )
        
        # 定义SSE事件生成器函数
        async def generate_sse_events():
            # 发送连接建立的消息
            yield "event: connected\ndata: {\"status\": \"connected\"}\n\n"
            
            card_count = 0
            for window_pages in windows:
                try:
                    # 准备页面内容
                    content_list = [
                        MaterialContent(material_id=request.material_id, page_number=page_num)
                        for page_num in window_pages
                    ]
                    
                    # 获取页面内容
                    content = crud_material.get_material_content(db, content_list)
                    app_logger.info(f"获取到的页面内容: {content[:200]}...")  # 只记录前200个字符
                    
                    # 生成知识卡片
                    card_content = analyzer.analyze_text(content)
                    app_logger.info(f"生成的知识卡片标题: {card_content['title']}")
                    
                    # 创建知识卡片并存储到数据库
                    card = crud_knowledge_card.create_knowledge_card(
                        db=db,
                        card=KnowledgeCardCreate(
                            title=card_content['title'],
                            summary=card_content['summary'],
                            html_content=card_content['html_content'],
                            page_number=",".join(map(str, window_pages)),
                            material_id=request.material_id
                        ),
                        user_id=current_user.id
                    )

                    # 更新 card_status 的值
                    update_material_card_status(db, request.material_id, window_pages, current_user.id)

                    # 转换响应格式
                    card_dict = {
                        "id": card.id,
                        "title": card.title,
                        "summary": card.summary,
                        "html_content": card.html_content,
                        "page_number": card.page_number,
                        "material_title": material.title,
                        "created_at": str(card.created_at),
                        "updated_at": str(card.updated_at)
                    }
                    
                    # 每个卡片分配一个唯一ID
                    card_count += 1
                    
                    # 构造SSE格式的事件
                    # 格式: event: <事件名>\nid: <事件ID>\ndata: <JSON数据>\n\n
                    event_data = {
                        "type": "card",
                        "data": card_dict
                    }
                    
                    sse_message = f"id: {card_count}\nevent: card\ndata: {json.dumps(event_data)}\n\n"
                    yield sse_message
                    
                    # 给前端一点时间处理每个卡片
                    await asyncio.sleep(0.1)
                    
                except Exception as e:
                    app_logger.error(f"生成知识卡片失败: {str(e)}")
                    error_event = {
                        "type": "error",
                        "data": {"error": str(e)}
                    }
                    yield f"event: error\ndata: {json.dumps(error_event)}\n\n"
            
            # 发送完成消息
            yield f"event: complete\ndata: {{\"status\": \"complete\", \"total\": {card_count}}}\n\n"
        
        # 返回SSE格式的流式响应
        return StreamingResponse(
            generate_sse_events(),
            media_type="text/event-stream",  # SSE的标准媒体类型
            headers={
                "Cache-Control": "no-cache",
                "Connection": "keep-alive",
                "X-Accel-Buffering": "no"  # 禁用nginx缓冲
            }
        )
        
    except Exception as e:
        app_logger.error(f"生成知识卡片过程中发生错误: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


